
#include "graphics.c"
#include "sounds.c"
#include "buttons.c"
#include <avr/interrupt.h>
#include <stdio.h>

int8_t p1x;
int8_t p2x;
uint8_t level = 0;
uint8_t lives = 3;
uint8_t canShoot = 1;

enum
{
	intro,
	alive,
	levelComplete,
	win,
	lose
} gameState = intro;

typedef struct {
   int8_t x;
   int8_t y;
} bullet;

uint8_t p1ActiveBullets = 0;
uint8_t p2ActiveBullets = 0;
bullet p1Bullet[4];
bullet p2Bullet[4];

void RemoveAllBullets()
{
	cli();
	p1ActiveBullets = 0;
	p2ActiveBullets = 0;
	sei();
}

void RemoveBullet(uint8_t player, uint8_t bulletnum)
{
	uint8_t j;
	if (player == 1)
	{
		cli();
		p1ActiveBullets --;
		for (j = bulletnum; j < p1ActiveBullets; j ++)
		{
			p1Bullet[j] = p1Bullet[j + 1];
		}
		sei();
	}
	else
	{
		cli();
		p2ActiveBullets --;
		for (j = bulletnum; j < p2ActiveBullets; j ++)
		{
			p2Bullet[j] = p2Bullet[j + 1];
		}
		sei();
	}
}

void CheckResetButton()
{
	cli();
	if (LeftCircleButton())
	{
		RemoveAllBullets();
		gameState = intro;
		lives = 3;
		level = 0;
		p1x = 3;
		p2x = 4;
	}
	EndButtons();
	sei();
}

void CheckButtons()
{
	cli();
	if (LeftArrowButton())
	{
		p1x = (p1x + 1) % 8;
	}
	if (RightArrowButton())
	{
		if (p1x == 0) p1x = 8;
		p1x = p1x - 1;
		
	}
	sei();
	uint8_t i;
	for (i = 0; i < p2ActiveBullets; i ++)
	{
		if (p2Bullet[i].y == 0 && p2Bullet[i].x == p1x)
		{
			lives--;
			if (lives == 0)
			{
				cli();
				gameState = lose;
				sei();
				
			}
		}
	}
	cli();
	if (RightCircleButton() && canShoot && p1ActiveBullets < 3)
	{
		p1Bullet[p1ActiveBullets].x = p1x;
		p1Bullet[p1ActiveBullets].y = 1;
		p1ActiveBullets ++;
		canShoot = 0;
	}
	EndButtons();
	sei();
}

void NextLevel()
{
	cli();
	p1x = 3;
	p2x = 4;
	gameState = alive;
	sei();
	level ++;
}

void MoveBullets()
{
	int8_t i;
	// enemy bulets
	
	for (i = p2ActiveBullets - 1; i >= 0; i --)
	{
		cli();
		p2Bullet[i].y --;
		sei();
		if (p2Bullet[i].y == -1)
		{
			RemoveBullet(2, i);
		}
		else if (p2Bullet[i].y == 0 && p2Bullet[i].x == p1x)
		{
			lives--;
			RemoveBullet(2, i);
			if (lives == 0)
			{
				RemoveAllBullets();
				cli();
				gameState = lose;
				sei();
			}
		}
	}
	
	// player bulets
	for (i = p1ActiveBullets - 1; i >= 0; i --)
	{
		cli();
		p1Bullet[i].y ++;
		sei();
		if (p1Bullet[i].y == 8)
		{
			RemoveBullet(1, i);
		}
		else if (p1Bullet[i].y == 7 && p1Bullet[i].x == p2x)
		{
			RemoveAllBullets();
			cli();
			gameState = levelComplete;
			sei();
		}
	}
	canShoot = 1;
}

void happySound()
{
	PlayToneNote("highdsharp", 200);
	PlayToneNote("highe", 200);
	PlayToneNote("highfsharp", 150);
}

void winSound()
{
	PlayToneNote("highe", 300);
	PlayToneNote("pause", 50);
	PlayToneNote("higha", 100);
	PlayToneNote("pause", 50);
	PlayToneNote("higha", 300);
	PlayToneNote("pause", 50);
	PlayToneNote("highe", 100);
	PlayToneNote("pause", 50);
	PlayToneNote("highe", 300);
	PlayToneNote("pause", 50);
	PlayToneNote("highb", 100);
	PlayToneNote("pause", 50);
	PlayToneNote("highb", 400);
	PlayToneNote("pause", 50);
	PlayToneNote("higha", 400);
	PlayToneNote("pause", 50);
	PlayToneNote("highe", 200);
	PlayToneNote("pause", 50);
	PlayToneNote("highd", 200);
	PlayToneNote("pause", 500);
	PlayToneNote("highe", 400);
}

void sadSound()
{
	PlayToneNote("midasharp", 200);
	PlayToneNote("midf", 200);
	PlayToneNote("mide", 600);
}

void loseSound()
{
	PlayToneNote("midg", 200);
	PlayToneNote("pause", 50);
	PlayToneNote("midgflat", 200);
	PlayToneNote("pause", 50);
	PlayToneNote("midf", 200);
	PlayToneNote("pause", 50);
	PlayToneNote("midd", 100);
	PlayToneNote("pause", 50);
	PlayToneNote("middflat", 100);
	PlayToneNote("pause", 50);
	PlayToneNote("midd", 200);
	PlayToneNote("pause", 50);
	PlayToneNote("middflat", 200);
}

void introSound()
{
	char *note[31] = {"mide", "pause", "mide", "pause", "mide", "pause", 
		"mide", "pause", "midf", "pause", "midf", "pause", "mide", "pause", "mide", "pause", "midf", "pause", "mide", "pause", "mide", "pause", "midg", "pause", "mide", "pause", "midf", "pause", "mide", "pause", "mide"};
	int duration[31] = {150,50,100,50,150,50,100,50,100,50,100,50,100,50,100,50,100,50,100,50,100,50,200,50,100,50,100,50,100,50,100};
	int length = 31;
	playSound(note, duration, length);
}

uint8_t updateFrequency = 100;

void Game1()
{
	int8_t i;
	while (1)
	{
		if (gameState == intro)
		{
			introSound();
			NextLevel();
		}
		else if (gameState == alive)
		{
			for (i = updateFrequency - 1; i >= 0; i --)
			{
				if (i == 0)
				{
					// move enemy
					cli();
					p2x = (p2x + 1) % 8;
					sei();
					MoveBullets();
					//enemy fire
					cli();
					if (p1x == p2x && p2ActiveBullets <= 3)
					{
						p2Bullet[p2ActiveBullets].x = p2x;
						p2Bullet[p2ActiveBullets].y = 6;
						p2ActiveBullets ++;
					}
					sei();
				}
				CheckButtons();
				delay(1);
			}
		}
		else if (gameState == levelComplete)
		{
			if (level == 20)
			{
				cli();
				gameState = win;
				sei();
				winSound();
				while (gameState == win)
				{
					CheckResetButton();
				}
			}
			else
			{
				happySound();
				NextLevel();
				updateFrequency -= 5;
			}
		}
		else if (gameState == lose)
		{
			sadSound();
			delay(200);
			loseSound();
			while (gameState == lose)
			{
				CheckResetButton();
			}
		}
	}
}

void Draw()
{
	uint8_t i;
	while (1)
	{
		if (gameState == intro)
		{
			char* colours[5] = {"RED", "BLUE", "GREEN", "WHITE", "PURPLE"};
			for (i = 0; i < 5; i ++)
			{
				DrawPlane(colours[i]);
				drawFrameBuffer();
				drawFrameBuffer();
				drawFrameBuffer();
				drawFrameBuffer();
				drawFrameBuffer();
			}
		}
		else if (gameState == alive)
		{
			ClearScreen();
			DrawPixel(p1x, 0, "BLUE");
			DrawPixel(p2x, 7, "RED"); // will change colours depending on level
			
			for (i = 0; i < p1ActiveBullets; i ++)
			{
				DrawPixel(p1Bullet[i].x, p1Bullet[i].y, "PURPLE");
			}
			for (i = 0; i < p2ActiveBullets; i ++)
			{
				DrawPixel(p2Bullet[i].x, p2Bullet[i].y, "GREEN");
			}
			drawFrameBuffer();
		}
		else if (gameState == levelComplete)
		{
			ClearScreen();
			for (i = 0; i < 8; i ++)
			{
				DrawColumn(i, "BLUE");
				drawFrameBuffer();
				delay(2);
			}
		}
		else if (gameState == lose)
		{
			ClearScreen();
			DrawRect(0, 0, 7, 7, "RED");
			while(1)
			{
				drawFrameBuffer();
			}
		}
	}
}